#include <agent/agent.h>
bool Agent::InitGLFW(){
    if(!glfwInit())return false;
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
	glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	glfwWindowHint(GLFW_SAMPLES, getValue("MultiSamples").asInt());
	if(!getValue("resizable").asBool())glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
	if(!getValue("hasBoard").asBool())glfwWindowHint(GLFW_DECORATED, GL_FALSE);
	if(getValue("alwaysTop").asBool())glfwWindowHint(GLFW_FLOATING, GL_TRUE);
	glfwWindowHint(GLFW_DEPTH_BITS, 32);
	if(getValue("alpha").asBool())glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);
	//some operating system can't support the alpha window.
	m_window = glfwCreateWindow(getValue("width").asInt(), 
		getValue("height").asInt(), 
		getValue("title").asCString(), nullptr, nullptr);
	if (m_window == nullptr)return false;
	Json::Value pos = getValue("position");
    glfwSetWindowPos(m_window,pos[0].asInt(),pos[1].asInt());
	glfwMakeContextCurrent(m_window);

	if (gl3wInit() != 0)return false;

	glfwSwapInterval(getValue("Vsync").asInt());
	glEnable(GL_MULTISAMPLE);
	glEnable(GL_DEPTH_TEST);
	return true;
}
void Agent::Thread_load(shared_ptr<IAgentComponent> componet){
	componet->Init();
	componet->loadDone = true;
	mutex_load_count.lock();
	haveLoadDone++;
	if(haveLoadDone==components.size())allLoadDone = true;
	mutex_load_count.unlock();
}
bool Agent::Init(){
    if(!InitGLFW())return false;
    for(auto&& component : components)
    {
		//thread thd(&Agent::Thread_load,this,component.second);
		//thd.detach();
		//component.second->Init();
		Thread_load(component.second);
    }
	return true;
}
void Agent::Update(){
	for(auto&& i : components)
		if(CheckComponentLoad(i.second))i.second->BeforeUpdate();
    UpdateMessage();
	for(auto&& i : components)
		if(CheckComponentLoad(i.second))i.second->Update();
	for(auto&& i : components)
		if(CheckComponentLoad(i.second))i.second->AfterUpdate();
}
bool Agent::ShouldClose(){
    return glfwWindowShouldClose(m_window);
}
GLFWwindow * Agent::GetWindow(){
    return m_window;
}
Agent::Agent() : Config("resource/config/agent.json"){
	ReadConfig();
}
void Agent::Event(){
    glfwSwapBuffers(m_window);
	glfwPollEvents();
}
void Agent::Clear(){
    glClearColor(backcolor[0],backcolor[1],backcolor[2],backcolor[3]);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
Agent::~Agent(){
	for(auto&& i : components)
		if(CheckComponentLoad(i.second))i.second->BeforeEnd();
	/*for(auto&& i : components)
		delete i.second;*/
	//you can't delete shared_ptr by your own
	//it's birth and die all controlled by factory
	glfwDestroyWindow(m_window);
	glfwTerminate();
}
void Agent::ReadConfig(){
	Json::Value color_json = getValue("backcolor");
	for(int i=0;i<4;++i)backcolor[i]=color_json[i].asFloat();
}
void Agent::AddComponent(string componentKey,shared_ptr<IAgentComponent> component){
	components[componentKey] = component;
	component->agent = this;
}
IAgentComponent::IAgentComponent(AgentComponentType m_type,bool loadDepend){
	this->loadDepend = loadDepend;
	this->m_type = m_type;
}
void Agent::UpdateMessage(){
	mutex_messageList.lock();
	for(auto &&message : messageList)
		for(auto&& component : components)
			if(CheckComponentLoad(component.second))component.second->PollMessage(message);
	messageList.clear();
	mutex_messageList.unlock();
}
bool Agent::CheckComponentLoad(shared_ptr<IAgentComponent> component){
	if(component->loadDone)
		if(component->loadDepend || allLoadDone)
			return true;
	return false;
}